package ua.com.stormlabs.tiny.licenseserver.controllers;

import org.jetbrains.annotations.NotNull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import ua.com.stormlabs.tiny.licenseserver.storage.RequestResult;

import java.util.*;

/**
 * User: Yuriy Sobko
 * Date: 4/12/12
 */
public class DataTableUtils {

    private static final Logger log = LoggerFactory.getLogger(DataTableUtils.class);

    private DataTableUtils() {
    }

    @NotNull
    public static Pageable parseFetchLimits(Map<String, Object> parameters) {
        if (parameters == null) {
            return new PageRequest(0, 10);
        }

        int offset = parseInt(DataTableRequestParam.RECORDS_FROM.getValue(), parameters);
        int pageSize = parseInt(DataTableRequestParam.RECORDS_PAGE_SIZE.getValue(), parameters);
        return new PageRequest(offset / pageSize, pageSize, new Sort(formSortingColumnsNames(parameters))) {
        };
    }

    @NotNull
    public static Map<String, Object> wrapResult(RequestResult searchResult, Map<String, Object> parameters) {
        Map<String, Object> wrapper = new LinkedHashMap<String, Object>();
        wrapper.put(DataTableRequestParam.TOTAL_RECORDS.getValue(), searchResult.getTotalCount());
        wrapper.put(DataTableRequestParam.FILTERED_RECORDS.getValue(), searchResult.getTotalCount());
        wrapper.put(DataTableRequestParam.RESULT_DATA.getValue(), searchResult.getResult());
        wrapper.put(DataTableRequestParam.REQUEST_VERSION.getValue(), parameters.get(DataTableRequestParam.REQUEST_VERSION.getValue()));
        return wrapper;
    }

    @NotNull
    private static List<Sort.Order> formSortingColumnsNames(Map<String, Object> parameters) {
        if (parameters == null) {
            return Collections.emptyList();
        }

        int sortingColsCount = parseInt(DataTableRequestParam.SORT_COLUMNS_COUNT.getValue(), parameters);
        if (sortingColsCount <= 0) {
            return Collections.emptyList();
        }

        List<Sort.Order> orders = new LinkedList<>();
        for (int i = 0; i < sortingColsCount; i++) {
            String sortingColumnNum = parseString(DataTableRequestParam.SORT_COLUMN_INDEX_PREFIX.getValue() + i,
                    parameters);
            String sortingColumnName = parseString(DataTableRequestParam.SORT_COLUMN_NAME_PREFIX.getValue() + sortingColumnNum,
                    parameters);
            String sortingType = parseString(DataTableRequestParam.SORT_DIRECTION_PREFIX.getValue() + i,
                    parameters);
            switch (sortingType) {
                case "asc":
                    orders.add(new Sort.Order(Sort.Direction.ASC, sortingColumnName));
                    break;
                case "desc":
                    orders.add(new Sort.Order(Sort.Direction.DESC, sortingColumnName));
                    break;
                default:
                    log.error("Unexpected sorting type [" + sortingType + "]. Setting to ascending");
                    orders.add(new Sort.Order(Sort.Direction.ASC, sortingColumnName));
                    break;
            }
        }

        return orders;
    }

    private static Integer parseInt(String paramName, Map<String, Object> parameters) {
        Object paramValue = parseParameterValue(paramName, parameters);
        if (paramValue == null) {
            return null;
        }
        return Integer.parseInt((String) paramValue);
    }

    private static String parseString(String paramName, Map<String, Object> parameters) {
        Object paramValue = parseParameterValue(paramName, parameters);
        if (paramValue == null) {
            return null;
        }
        return (String) paramValue;
    }

    private static String parseParameterValue(String paramName, Map<String, Object> parameters) {
        Object paramValue = parameters.get(paramName);
        if (paramValue == null) {
            return null;
        }
        if (paramValue instanceof String) {
            return (String) paramValue;
        }
        if (paramValue instanceof String[]) {
            String[] values = (String[]) paramValue;
            if (values.length > 0) {
                return values[0];
            }
        }
        return null;
    }
}
